package com.ruoyi.framework.config

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties
import com.alibaba.druid.util.Utils
import com.ruoyi.common.enums.DataSourceType
import com.ruoyi.common.utils.spring.SpringUtils
import com.ruoyi.framework.config.properties.DruidProperties
import com.ruoyi.framework.datasource.DynamicDataSource
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.web.servlet.FilterRegistrationBean
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Primary
import java.io.IOException
import javax.servlet.*
import javax.servlet.FilterConfig
import javax.sql.DataSource

/**
 * druid 配置多数据源
 *
 * @author ruoyi
 */
@Configuration
open class DruidConfig {
    @Bean
    @ConfigurationProperties("spring.datasource.druid.master")
    open fun masterDataSource(druidProperties: DruidProperties): DataSource {
        val dataSource = DruidDataSourceBuilder.create().build()
        return druidProperties.dataSource(dataSource)
    }

    @Bean
    @ConfigurationProperties("spring.datasource.druid.slave")
    @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = ["enabled"], havingValue = "true")
    open fun slaveDataSource(druidProperties: DruidProperties): DataSource {
        val dataSource = DruidDataSourceBuilder.create().build()
        return druidProperties.dataSource(dataSource)
    }

    @Bean(name = ["dynamicDataSource"])
    @Primary
    open fun dataSource(masterDataSource: DataSource): DynamicDataSource {
        val targetDataSources: MutableMap<Any, Any> = mutableMapOf()
        targetDataSources[DataSourceType.MASTER.name] = masterDataSource
        setDataSource(targetDataSources, DataSourceType.SLAVE.name, "slaveDataSource")
        return DynamicDataSource(masterDataSource, targetDataSources)
    }

    /**
     * 设置数据源
     *
     * @param targetDataSources 备选数据源集合
     * @param sourceName 数据源名称
     * @param beanName bean名称
     */
    fun setDataSource(targetDataSources: MutableMap<Any, Any>, sourceName: String, beanName: String?) {
        try {
            val dataSource = SpringUtils.getBean<DataSource>(beanName)
            targetDataSources[sourceName] = dataSource
        } catch (_: Exception) {
        }
    }

    /**
     * 去除监控页面底部的广告
     */
    @Bean
    @ConditionalOnProperty(name = ["spring.datasource.druid.statViewServlet.enabled"], havingValue = "true")
    open fun removeDruidFilterRegistrationBean(properties: DruidStatProperties): FilterRegistrationBean<*> {
        // 获取web监控页面的参数
        val config = properties.statViewServlet
        // 提取common.js的配置路径
        val pattern = if (config.urlPattern != null) config.urlPattern else "/druid/*"
        val commonJsPattern = pattern.replace("\\*".toRegex(), "js/common.js")
        val filePath = "support/http/resources/js/common.js"
        // 创建filter进行过滤
        val filter: Filter = object : Filter {
            @Throws(ServletException::class)
            override fun init(filterConfig: FilterConfig) {
            }

            @Throws(IOException::class, ServletException::class)
            override fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
                chain.doFilter(request, response)
                // 重置缓冲区，响应头不会被重置
                response.resetBuffer()
                // 获取common.js
                var text = Utils.readFromResource(filePath)
                // 正则替换banner, 除去底部的广告信息
                text = text.replace("<a.*?banner\"></a><br/>".toRegex(), "")
                text = text.replace("powered.*?shrek.wang</a>".toRegex(), "")
                response.writer.write(text)
            }

            override fun destroy() {}
        }
        val registrationBean: FilterRegistrationBean<*> = FilterRegistrationBean<Filter>()
        registrationBean.filter=filter
        registrationBean.addUrlPatterns(commonJsPattern)
        return registrationBean
    }
}
